package org.jecat.pusher;

import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Hashtable;




public class Channel
{
	public static final String channelName = "channelName" ;  
	
	public Channel(String sChannelName)
	{
		m_sChannelName = sChannelName ;
	}

	public void add(Session session)
	{
		String sId = session.id() ;
		m_totalSessions ++ ;
		
		// 匿名
		if(sId==null)
		{
			synchronized(m_arrGuests)
			{
				m_arrGuests.add(session) ;
				m_anonymousSessions ++ ;
			}
			
			Server.log(info()+"a new anonymous session come in.") ;
		}
		
		else
		{
			synchronized(m_arrUsers)
			{
				ArrayList<Session> arrUserSessions = m_arrUsers.get(sId) ;
				if( arrUserSessions==null )
				{
					arrUserSessions = new ArrayList<Session>() ;
					m_arrUsers.put(sId,arrUserSessions) ;
				}
				
				synchronized(arrUserSessions)
				{
					if(!arrUserSessions.contains(session))
					{
						arrUserSessions.add(session) ;
					}
				}
			}
			
			Server.log(info()+" a new session(id:"+sId+") come in.") ;
		}
	}
	
	public void remove(Session session)
	{
		String sId = session.id() ;
		
		// 匿名
		if(sId==null)
		{
			synchronized(m_arrGuests)
			{
				if(m_arrGuests.contains(session))
				{
					m_arrGuests.remove(session) ;
					m_totalSessions -- ;
					m_anonymousSessions -- ;
				}
			}
			
			Server.log(info()+" a anonymous session close.") ;
		}
		
		else
		{
			synchronized(m_arrUsers)
			{
				ArrayList<Session> arrUserSessions = m_arrUsers.get(sId) ;
				if(arrUserSessions!=null)
				{
					synchronized(arrUserSessions)
					{
						while(arrUserSessions.contains(session))
						{
							arrUserSessions.remove(session) ;
							m_totalSessions -- ;
						}
						
						if(arrUserSessions.size()<1)
						{
							m_arrUsers.remove(sId) ;
						}
					}
				}
			}

			Server.log(info()+" a session(id:"+sId+") close.") ;
		}
	}
	
	public static Channel findChannel(Hashtable<String,Channel> mapChannels,Session session)
	{
		String sChannelName = (String) session.channelName() ;
		if(sChannelName==null)
		{
			return null ;
		}
		
		return mapChannels.get(sChannelName) ;
	}
		

	public void pushData(Request aReq, SocketChannel from)
	{
		String sData = aReq.get("data","") ;
		if(sData.length()<1)
		{
			Server.send("missing parameter channel or parameter invalid.",from) ;
			return ;
		}

		int nPushUsers = 0 ;
		String[] arrIds = aReq.getParams("id") ;

		// 广播
		if( arrIds==null || arrIds.length==0 )
		{
			// 匿名用户
			synchronized(m_arrGuests)
			{
				for(Session session:m_arrGuests )
				{
					Server.sendPackage(sData,session.socket()) ;
					nPushUsers ++ ;
				}
			}
			
			// 登录用户
			synchronized(m_arrUsers)
			{
				for(ArrayList<Session> sessionList:m_arrUsers.values())
				{
					if( sessionList!=null )
					{
						synchronized(sessionList)
						{
							for(Session session:sessionList)
							{
								Server.sendPackage(sData,session.socket()) ;
								nPushUsers ++ ;
							}
						}
					}
				}
				
			}
		}
		
		// 指定用户
		else
		{
			for(String sId:arrIds)
			{
				synchronized(m_arrUsers)
				{
					ArrayList<Session> arrSessions = m_arrUsers.get(sId) ;
					if( arrSessions!=null )
					{
						synchronized(arrSessions)
						{
							for(Session session:arrSessions)
							{
								Server.sendPackage(sData,session.socket()) ;
							}
						}
					}
					
					nPushUsers ++ ;
				}
			}
		}

		Server.send(String.valueOf(nPushUsers),from) ;
		Server.log(info()+" push data(bytes:"+sData.length()+") to "+nPushUsers+" sessions. "+(arrIds==null?"": (""+arrIds.length+" id") )) ;
	}
	
	public String info()
	{
		return "<channel:"+m_sChannelName+"(anonymous:"+m_anonymousSessions+"/total:"+m_totalSessions+")>" ;
	}

	
	private ArrayList<Session> m_arrGuests = new ArrayList<Session>() ;
	private Hashtable<String,ArrayList<Session>> m_arrUsers = new Hashtable<String,ArrayList<Session>>() ;

	private String m_sChannelName = "" ;
	
	private Integer m_totalSessions = new Integer(0) ;
	private Integer m_anonymousSessions = new Integer(0) ;
	
}
